package com.ztgf.pay.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.blue.util.MoneyUtil;
import com.blue.util.StringUtil;
import com.trz.netwk.api.system.TrdMessenger;
import com.trz.netwk.api.trd.*;
import com.trz.netwk.api.vo.ReFundBillInfo;
import com.ztgf.common.constant.Result;
import com.ztgf.common.enums.CodeEnum;
import com.ztgf.common.utils.BigDecimalUtils;
import com.ztgf.common.utils.DateUtils;
import com.ztgf.common.utils.StrUtils;
import com.ztgf.order.models.bo.OrderPayBO;
import com.ztgf.order.models.service.IOrderPayRelationService;
import com.ztgf.pay.async.IAsyncService;
import com.ztgf.pay.models.dto.PayHttpLogDTO;
import com.ztgf.pay.models.dto.PayOrderDTO;
import com.ztgf.pay.models.dto.PayUserDTO;
import com.ztgf.pay.models.service.*;
import com.ztgf.pay.models.vo.PayUserBalanceVO;
import com.ztgf.shopping.models.service.shop.IShopPayRefundLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import javax.annotation.Resource;
import com.ztgf.pay.common.config.YmlConfig;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.ztgf.pay.mapper.PayOrderRepayMapper;
import com.ztgf.pay.models.bo.PayOrderRepaySaveBO;
import com.ztgf.pay.models.dto.PayOrderRepayDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 退款订单控制器
 *
 * @author mxli
 * @Date 2020-07-30 12:13:30
 */
@DubboService
@Slf4j
public class PayOrderRepayServiceImpl extends ServiceImpl<PayOrderRepayMapper, PayOrderRepayDTO> implements IPayOrderRepayService{

    @Resource
    private YmlConfig ymlConfig;

    @Autowired
    private IPayHttpLogService httpLogService;

    @Autowired
    private IPayOrderService payOrderService;

    @Autowired
    private IAsyncService asyncService;

    @Autowired
    private IPayUserService payUserService;

    /**
     * 余额退款
     * @param saveBO
     * @return
     */
    @Override
    public Result<PayOrderRepayDTO> saveBalanceOrderRepay(PayOrderRepaySaveBO saveBO) {
        if(saveBO.getOriginalOrderId() == null || saveBO.getMoney() == null || saveBO.getMoney().doubleValue() <= 0){
            return new Result(CodeEnum.FAIL_100002);
        }

        //添加请求日志
        PayHttpLogDTO logDTO = new PayHttpLogDTO();
        boolean httpSuccess = false;
        PayOrderDTO orderDTO = payOrderService.selectById(saveBO.getOriginalOrderId());
        if(orderDTO == null || orderDTO.getStatus() != 2 || saveBO.getMoney().doubleValue() > orderDTO.getMoney().doubleValue()){
            return new Result(CodeEnum.FAIL_100002);
        }
        Wrapper wrapper = new EntityWrapper();
        PayOrderRepayDTO repayDTO = new PayOrderRepayDTO();
        Long id = ymlConfig.getPkId();
        repayDTO.setId(id);
        repayDTO.setOriginalOrderId(saveBO.getOriginalOrderId());
        repayDTO.setBusinessOrderId(saveBO.getBusinessOrderId());
        repayDTO.setMoney(saveBO.getMoney());
        repayDTO.setStatus(0);
        repayDTO.setType(0);
        repayDTO.setNotifyUrl(saveBO.getNotifyUrl());
//        repayDTO.setZjBusinessId();
        this.insert(repayDTO);
        String msg = CodeEnum.FAIL_200024.getMsg();
        try {

            // 2. 实例化交易对象
            TrdT4041Request trdRequest = new TrdT4041Request();
            trdRequest.setMsghd_trdt(DateUtils.dateToStr(new Date(),DateUtils.DATE_FORMAT_DATESHORTDAY)); /** 交易日期 */
            trdRequest.setSrl_ptnsrl(id.toString());/** 合作方交易流水号 */
            trdRequest.setTrsflag("A00");/** 业务标示(A00:普通退款) */
            trdRequest.setDtrcd("PAY");/** 原交易标志 UIN:渠道入金 ENTRCV:收款业务 JUHEPAY:聚合支付 PAY：订单支付 INPAY：入金支付 */
            trdRequest.setDptnsrl(saveBO.getOriginalOrderId().toString());/** 原交易的合作方交易流水号 */
            trdRequest.setUsage(saveBO.getUsage());/** 退款原因 */
            trdRequest.setAmt_aclamt(BigDecimalUtils.multiply(saveBO.getMoney(), 100).longValue());/** 发生额(资金单位:分) */
//            trdRequest.setAmt_payfee(amt_payfee);//付款方手续费
//            trdRequest.setAmt_payeefee(amt_payeefee);//收款方手续费
//
//            trdRequest.setAmt_repayfee(amt_repayfee);//原付款方手续费退款金额
//            trdRequest.setAmt_repayeefee(amt_repayeefee);//原收款方手续费退款金额

            // 3. 报文处理
            trdRequest.process();
            System.out.println("请求报文[" + trdRequest.getRequestPlainText() + "]");
            System.out.println("签名原文[" + trdRequest.getRequestMessage() + "]");
            System.out.println("签名数据[" + trdRequest.getRequestSignature() + "]");
            logDTO.setParams(trdRequest.getRequestPlainText());
            logDTO.setWaterId(id);

            // 4. 与融资平台通信
            TrdMessenger trdMessenger = new TrdMessenger();
            // message
            String respMsg = trdMessenger.send(trdRequest);

            // 5. 处理交易结果
            TrdT4041Response trdResponse = new TrdT4041Response(respMsg);
            System.out.println("响应报文[" + trdResponse.getResponsePlainText() + "]");

            logDTO.setReturnValue(trdResponse.getResponsePlainText());
            logDTO.setBusinessStatus(trdResponse.getMsghd_rspcode());
            logDTO.setBusinessNotes(trdResponse.getMsghd_rspmsg());
            logDTO.setParams(trdRequest.getRequestPlainText());
            logDTO.setStatus(0);

            // 交易成功 000000
            if ("000000".equals(trdResponse.getMsghd_rspcode())) {
                // ！！！ 在这里添加合作方处理逻辑！！！
                httpSuccess = true;
                System.out.println("[msghd_rspmsg]=[" + trdResponse.getMsghd_rspmsg() + "]"); // 返回信息
                System.out.println("[srl_platsrl]=[" + trdResponse.getSrl_platsrl() + "]"); // 平台交易流水号

                System.out.println("[state]=[" + trdResponse.getState() + "]"); // 退款结果:1退款成功;2退款失败;3退款处理中
                System.out.println("[resttime]=[" + trdResponse.getResttime() + "]"); // 退款成功/失败时间(渠道通知时间)格式:YYYYMMDDHH24MISS
                System.out.println("[opion]=[" + trdResponse.getOpion() + "]"); // 失败原因

                updateDTO(trdResponse.getState(), repayDTO);

            }


        } catch (Exception e) {
            e.printStackTrace();
            log.error("TrdT4041Request 余额退款 is error", e);
            logDTO.setStatus(1);
            logDTO.setReturnValue("TrdT4041Request 余额退款 500");
        }

        //添加日志
        logDTO.setId(ymlConfig.getPkId());
        httpLogService.insert(logDTO);
        if(!httpSuccess){
            return new Result(CodeEnum.FAIL_200024.getCode(), msg);
        }
        return new Result(repayDTO);
    }

    /**
     * 网银退款
     * @param saveBO
     * @return
     */
    @Override
    public Result<PayOrderRepayDTO> saveOnlineBankOrderRepay(PayOrderRepaySaveBO saveBO) {
        if(saveBO.getOriginalOrderId() == null || saveBO.getMoney() == null || saveBO.getMoney().doubleValue() <= 0){
            return new Result(CodeEnum.FAIL_100002);
        }

        //添加请求日志
        PayHttpLogDTO logDTO = new PayHttpLogDTO();
        boolean httpSuccess = false;
        PayOrderDTO orderDTO = payOrderService.selectById(saveBO.getOriginalOrderId());
        if(orderDTO == null || orderDTO.getStatus() != 2 || saveBO.getMoney().doubleValue() > orderDTO.getMoney().doubleValue()){
            return new Result(CodeEnum.FAIL_100002);
        }

        PayOrderRepayDTO repayDTO = new PayOrderRepayDTO();
        Long id = ymlConfig.getPkId();
        repayDTO.setId(id);
        repayDTO.setOriginalOrderId(saveBO.getOriginalOrderId());
        repayDTO.setBusinessOrderId(saveBO.getBusinessOrderId());
        repayDTO.setMoney(saveBO.getMoney());
        repayDTO.setStatus(0);
        repayDTO.setType(1);
//        repayDTO.setZjBusinessId();
        repayDTO.setNotifyUrl(saveBO.getNotifyUrl());
        this.insert(repayDTO);
        String msg = CodeEnum.FAIL_200024.getMsg();
        try {

            /**
             * 2 实例化交易对象
             */
            TrdT4045Request trdRequest = new TrdT4045Request();
            trdRequest.setMsghd_trdt(DateUtils.dateToStr(new Date(),DateUtils.DATE_FORMAT_DATESHORTDAY)); /** 交易日期 */
            trdRequest.setSrl_ptnsrl(id.toString());/** 合作方交易流水号 */
            trdRequest.setTrsflag("A00");//业务标示A00:普通退款
            trdRequest.setDtrcd("INPAY_BC");//原交易标志ENTRCV_BC:收款分账业务 INPAY_BC：入金分账支付
            trdRequest.setDptnsrl(orderDTO.getMotherOrderId().toString());//原交易的合作方交易流水号:
//            trdRequest.setPayfee(MoneyUtil.toNumber(payfee).longValue());//付款方手续费
//            trdRequest.setRepayfee(MoneyUtil.toNumber(repayfee).longValue());//付款方手手续费退款金额

            List<ReFundBillInfo> billinfoList=new ArrayList<ReFundBillInfo>();

            ReFundBillInfo quyDak=new ReFundBillInfo();
            quyDak.setBillinfo_aclamt(BigDecimalUtils.multiply(saveBO.getMoney(), 100).longValue());//退款金额
            quyDak.setBillinfo_billno(orderDTO.getId().toString());//原明细支付单号
            quyDak.setBillinfo_usage(saveBO.getUsage());//退款原因
//            quyDak.setBillinfo_payeefee(MoneyUtil.toNumber(billinfo_payeefee[i]).longValue());//收款方手续费付款方
//            quyDak.setBillinfo_repayeefee(MoneyUtil.toNumber(billinfo_repayeefee[i]).longValue());//收款方手续费
            billinfoList.add(quyDak);

            trdRequest.setBillinfoList(billinfoList);
            /**
             * 3.报文处理
             */
            trdRequest.process();
            System.out.println("请求报文[" + trdRequest.getRequestPlainText() + "]");
            System.out.println("签名原文[" + trdRequest.getRequestMessage() + "]");
            System.out.println("签名数据[" + trdRequest.getRequestSignature() + "]");
            logDTO.setParams(trdRequest.getRequestPlainText());
            logDTO.setWaterId(id);

            /**
             * 4 和融资平台通信
             */
            TrdMessenger trdMessenger = new TrdMessenger();
            // responseMessage
            String respMsg = trdMessenger.send(trdRequest);
            TrdT4045Response  trdResponse=new TrdT4045Response(respMsg);
            System.out.println("响应报文[" + trdResponse.getResponsePlainText() + "]");

            logDTO.setReturnValue(trdResponse.getResponsePlainText());
            logDTO.setBusinessStatus(trdResponse.getMsghd_rspcode());
            logDTO.setBusinessNotes(trdResponse.getMsghd_rspmsg());
            logDTO.setParams(trdRequest.getRequestPlainText());
            logDTO.setStatus(0);

            // 交易成功 000000
            if ("000000".equals(trdResponse.getMsghd_rspcode())) {
                // ！！！ 在这里添加合作方处理逻辑！！！
                httpSuccess = true;
                System.out.println("[msghd_rspmsg]=[" + trdResponse.getMsghd_rspmsg() + "]"); // 返回信息
                System.out.println("[srl_platsrl]=[" + trdResponse.getSrl_platsrl() + "]"); // 平台交易流水号

                System.out.println("[state]=[" + trdResponse.getState() + "]"); // 退款结果:1退款成功;2退款失败;3退款处理中
                System.out.println("[resttime]=[" + trdResponse.getResttime() + "]"); // 退款成功/失败时间(渠道通知时间)格式:YYYYMMDDHH24MISS

                updateDTO(trdResponse.getState(), repayDTO);
            }


        } catch (Exception e) {
            e.printStackTrace();
            log.error("TrdT4041Request 余额退款 is error", e);
            logDTO.setStatus(1);
            logDTO.setReturnValue("TrdT4041Request 余额退款 500");
        }

        //添加日志
        logDTO.setId(ymlConfig.getPkId());
        httpLogService.insert(logDTO);
        if(!httpSuccess){
            return new Result(CodeEnum.FAIL_200024.getCode(), msg);
        }
        return new Result(repayDTO);
    }

    @Override
    public void saveOnlineBankRepayLog(PayOrderRepayDTO repayDTO) {
        if(repayDTO == null){
            return;
        }

        try {

            /**
             * 2 实例化交易对象
             */
            TrdT4047Request trdRequest = new TrdT4047Request();
            trdRequest.setMsghd_trdt(DateUtils.dateToStr(new Date(),DateUtils.DATE_FORMAT_DATESHORTDAY));// 交易日期
            trdRequest.setSrl_ptnsrl(repayDTO.getId().toString());// 合作方交易流水号

            /**
             * 3.报文处理
             */

            trdRequest.process();
            System.out.println("请求报文[" + trdRequest.getRequestPlainText() + "]");
            System.out.println("签名原文[" + trdRequest.getRequestMessage() + "]");
            System.out.println("签名数据[" + trdRequest.getRequestSignature() + "]");

            /**
             * 4 和融资平台通信
             */
            TrdMessenger trdMessenger = new TrdMessenger();

            // responseMessage
            String respMsg = trdMessenger.send(trdRequest);
            TrdT4047Response  trdResponse=new TrdT4047Response(respMsg);
            System.out.println("响应报文[" + trdResponse.getResponsePlainText() + "]");

            // 交易成功 000000
            if ("000000".equals(trdResponse.getMsghd_rspcode())) {
                // ！！！ 在这里添加合作方处理逻辑！！！
                updateDTO(trdResponse.getState(), repayDTO);
            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("TrdT4047Request 查询网银退款状态 is error", e);
        }
    }

    @Override
    public void saveBalanceRepayLog(PayOrderRepayDTO repayDTO) {
        if(repayDTO == null){
            return;
        }

        try {

            // 2. 实例化交易对象
            TrdT4043Request trdRequest = new TrdT4043Request();
            trdRequest.setMsghd_trdt(DateUtils.dateToStr(new Date(),DateUtils.DATE_FORMAT_DATESHORTDAY)); /** 交易日期 */
            trdRequest.setSrl_ptnsrl(repayDTO.getId().toString());/** 合作方交易流水号 */

            // 3. 报文处理
            trdRequest.process();
            System.out.println("请求报文[" + trdRequest.getRequestPlainText() + "]");
            System.out.println("签名原文[" + trdRequest.getRequestMessage() + "]");
            System.out.println("签名数据[" + trdRequest.getRequestSignature() + "]");

            // 4. 与融资平台通信
            TrdMessenger trdMessenger = new TrdMessenger();
            // message
            String respMsg = trdMessenger.send(trdRequest);

            // 5. 处理交易结果
            TrdT4043Response trdResponse = new TrdT4043Response(respMsg);
            System.out.println("响应报文[" + trdResponse.getResponsePlainText() + "]");

            // 交易成功 000000
            if ("000000".equals(trdResponse.getMsghd_rspcode())) {
                // ！！！ 在这里添加合作方处理逻辑！！！
//                System.out.println("[msghd_rspmsg]=[" + trdResponse.getMsghd_rspmsg() + "]"); // 返回信息
//                System.out.println("[srl_ptnsrl]=[" + trdResponse.getSrl_ptnsrl() + "]"); // T4041交易的合作方交易流水号
//                System.out.println("[srl_platsrl]=[" + trdResponse.getSrl_platsrl() + "]"); // T4041交易的平台交易流水号
//
//                System.out.println("[trsflag]=[" + trdResponse.getTrsflag() + "]"); // 业务标示:A00普通退款
//                System.out.println("[dtrcd]=[" + trdResponse.getDtrcd() + "]"); // 原交易标志(ENTRCV:收款业务)
//                System.out.println("[dptnsrl]=[" + trdResponse.getDptnsrl() + "]"); // 原交易标志(ENTRCV:收款业务)
//                System.out.println("[usage]=[" + trdResponse.getUsage() + "]"); // 退款原因
//                System.out.println("[amt_aclamt]=[" + trdResponse.getAmt_aclamt() + "分]"); // 退款金额
//                System.out.println("[amt_ccycd]=[" + trdResponse.getAmt_ccycd() + "]"); // 币种，默认“CNY”
//
//                System.out.println("[state]=[" + trdResponse.getState() + "]"); // 退款结果:1退款成功;2退款失败;3退款处理中
//                System.out.println("[resttime]=[" + trdResponse.getResttime() + "]"); // 退款成功/失败时间(渠道通知时间)格式:YYYYMMDDHH24MISS
//                System.out.println("[opion]=[" + trdResponse.getOpion() + "]"); // 失败原因
//
//                System.out.println("[fdate]=[" + trdResponse.getFdate() + "]"); // 原交易日期
//                System.out.println("[ftime]=[" + trdResponse.getFtime() + "]"); // 原交易时间
//                System.out.println("[spec1]=[" + trdResponse.getSpec1() + "]"); // 备用1
//                System.out.println("[spec2]=[" + trdResponse.getSpec2() + "]"); // 备用2

                updateDTO(trdResponse.getState(), repayDTO);
            } else {
                updateDTO("2", repayDTO);
            }


        } catch (Exception e) {
            e.printStackTrace();
            log.error("TrdT4043Response 查询余额退款状态 is error", e);
        }
    }

    /**
     * 根据中金返回状态修改信息
     * @param state
     * @param repayDTO
     */
    @Override
    public void updateDTO(String state, PayOrderRepayDTO repayDTO){
        int status = 0;
        if("1".equals(state)){
//        if("1".equals(state) || "3".equals(state)){// 测试环境没有成功状态
            status = 2;
            //TODO: 业务系统要记录支付类型与支付订单id 退款时用
            if(StrUtils.isNotEmpty(repayDTO.getNotifyUrl())){
                if("0".equals(repayDTO.getNotifyUrl())){//缴年费
                    asyncService.notifyAnnualFee(repayDTO.getBusinessOrderId(), repayDTO.getId(), 1);
                } else if("1".equals(repayDTO.getNotifyUrl())){//订单
                    OrderPayBO orderPayBO = new OrderPayBO();
                    orderPayBO.setOrderId(repayDTO.getBusinessOrderId());
                    orderPayBO.setBusinessOrderWaterId(repayDTO.getBusinessOrderId());
                    orderPayBO.setRefundOrderId(repayDTO.getId());
                    orderPayBO.setOrderPayRelationId(repayDTO.getId());
                    orderPayBO.setType(0);
                    orderPayBO.setPayType(repayDTO.getType());
                    orderPayBO.setRefundStatus(2);
                    orderPayBO.setZjBusinessId(repayDTO.getZjBusinessId());
                    asyncService.notifyOrder(orderPayBO);
                    repayDTO.setNotifyStatus(1);
                } else if("2".equals(repayDTO.getNotifyUrl())){
                    OrderPayBO orderPayBO = new OrderPayBO();
                    orderPayBO.setOrderId(repayDTO.getBusinessOrderId());
                    orderPayBO.setBusinessOrderWaterId(repayDTO.getBusinessOrderId());
                    orderPayBO.setRefundOrderId(repayDTO.getId());
                    orderPayBO.setOrderPayRelationId(repayDTO.getId());
                    orderPayBO.setType(2);
                    orderPayBO.setPayType(repayDTO.getType());
                    orderPayBO.setRefundStatus(2);
                    orderPayBO.setZjBusinessId(repayDTO.getZjBusinessId());
                    asyncService.notifyOrder(orderPayBO);
                    repayDTO.setNotifyStatus(1);
                }
            }
        } else if("2".equals(state)){
            status = 3;
        } else {
            status = 1;
        }
//        status = 2;
        repayDTO.setStatus(status);
        int revision = repayDTO.getRevision();
        Wrapper wrapper = new EntityWrapper();
        wrapper.eq("id", repayDTO.getId());
        wrapper.eq("revision", revision);
        repayDTO.setRevision(revision + 1);
        this.update(repayDTO, wrapper);


        PayOrderDTO orderDTO = payOrderService.selectById(repayDTO.getOriginalOrderId());
        PayUserDTO userDTO = payUserService.getPayUserDTO(orderDTO.getPaymentUserId(), 1);
        saveRepayNoWithdrawMoney(userDTO, orderDTO, status);

    }

    @Override
    public Result saveRepayNoWithdrawMoney(PayUserDTO userDTO, PayOrderDTO orderDTO, int status) {
        if(userDTO != null && userDTO.getNoWithdrawMoneyInit().compareTo(BigDecimal.ZERO) > 0){
            //获取订单总金额
            BigDecimal orderMoney = this.baseMapper.getAllOrderBlanceMoney(userDTO.getUserId(), userDTO.getNoWithdrawMoneySetTime(), 0);
            //预售的退款金额
            BigDecimal repayOrderMoneyYS = this.baseMapper.getAllOrderBlanceMoney(userDTO.getUserId(), userDTO.getNoWithdrawMoneySetTime(), 1);
            //获取订单退款总金额
            BigDecimal repayOrderMoney = this.baseMapper.getAllRepayOrderBlanceMoney(userDTO.getUserId(), userDTO.getNoWithdrawMoneySetTime(), status);
            if(orderMoney == null){
                orderMoney = BigDecimal.ZERO;
            }
            if(repayOrderMoneyYS == null){
                repayOrderMoneyYS = BigDecimal.ZERO;
            }
            if(repayOrderMoney == null){
                repayOrderMoney = BigDecimal.ZERO;
            }
            BigDecimal noWithdrawMoney = userDTO.getNoWithdrawMoneyInit().subtract(orderMoney).add(repayOrderMoney).add(repayOrderMoneyYS);
            if(noWithdrawMoney.compareTo(BigDecimal.ZERO) > 0){
                userDTO.setNoWithdrawMoney(noWithdrawMoney);
                if(!payUserService.updateNoWithdrawMoney(userDTO).success()){
                    log.error("TrdT4041Request 余额退款 updateNoWithdrawMoney is error------:" + JSON.toJSONString(orderDTO));
                    return new Result(CodeEnum.FAIL_100011);
                }
            }
        } else {
            log.error("TrdT4041Request 余额退款 is error  PayUserDTO 付款人为空----：" + JSON.toJSONString(orderDTO));
            return new Result(CodeEnum.FAIL_100011);
        }
        return new Result();
    }

}
